using Lzfy_His_Service.Models;
using Lzfy_His_Service.Repositories;
using OfficeOpenXml;
using System.Text;

namespace Lzfy_His_Service.Services
{
    /// <summary>
    /// 退费情况查询服务实现
    /// </summary>
    public class RefundStatusService : IRefundStatusService
    {
        private readonly IRefundStatusRepository _refundStatusRepository;
        private readonly ILogger<RefundStatusService> _logger;

        public RefundStatusService(IRefundStatusRepository refundStatusRepository, ILogger<RefundStatusService> logger)
        {
            _refundStatusRepository = refundStatusRepository;
            _logger = logger;
        }

        /// <summary>
        /// 分页查询退费情况数据
        /// </summary>
        public async Task<RefundStatusQueryResponse> GetPagedAsync(RefundStatusQueryRequest request)
        {
            try
            {
                _logger.LogInformation("开始分页查询退费情况，页码: {PageIndex}, 页大小: {PageSize}", 
                    request.PageIndex, request.PageSize);

                var (data, totalCount) = await _refundStatusRepository.GetPagedAsync(
                    request.PageIndex - 1, // 转换为0基索引
                    request.PageSize,
                    request.Name,
                    request.IdNumber,
                    request.RefundResult,
                    request.CreateTimeStart,
                    request.CreateTimeEnd);

                var response = new RefundStatusQueryResponse
                {
                    Items = data.ToList(),
                    TotalCount = totalCount,
                    PageIndex = request.PageIndex,
                    PageSize = request.PageSize
                };

                _logger.LogInformation("分页查询退费情况完成，返回 {Count} 条记录，总数: {TotalCount}", 
                    response.Items.Count, totalCount);

                return response;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "分页查询退费情况失败");
                throw;
            }
        }

        /// <summary>
        /// 导出退费情况数据
        /// </summary>
        public async Task<byte[]> ExportAsync(RefundStatusExportRequest request)
        {
            try
            {
                _logger.LogInformation("开始导出退费情况数据，格式: {Format}", request.ExportFormat);

                // 获取总记录数
                var totalCount = await _refundStatusRepository.GetTotalCountAsync(
                    request.Name,
                    request.IdNumber,
                    request.RefundResult,
                    request.CreateTimeStart,
                    request.CreateTimeEnd);

                byte[] fileBytes;

                if (request.ExportFormat.ToLower() == "excel")
                {
                    // 如果数据量超过100万条，使用分批导出
                    if (totalCount > 1000000)
                    {
                        fileBytes = await ExportToMultipleExcelAsync(request, totalCount);
                    }
                    else
                    {
                        fileBytes = await ExportToExcelAsync(request);
                    }
                }
                else
                {
                    fileBytes = await ExportToCsvAsync(request);
                }

                _logger.LogInformation("导出退费情况数据完成，文件大小: {Size} bytes", fileBytes.Length);

                return fileBytes;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "导出退费情况数据失败");
                throw;
            }
        }

        /// <summary>
        /// 获取导出预估信息
        /// </summary>
        public async Task<RefundStatusExportEstimate> GetExportEstimateAsync(RefundStatusExportRequest request)
        {
            try
            {
                var totalCount = await _refundStatusRepository.GetTotalCountAsync(
                    request.Name,
                    request.IdNumber,
                    request.RefundResult,
                    request.CreateTimeStart,
                    request.CreateTimeEnd);
                
                // 估算文件大小（每条记录约200字节）
                var estimatedSizeBytes = totalCount * 200L;
                
                _logger.LogInformation("获取导出预估信息完成，总记录数: {TotalCount}, 预估大小: {EstimatedSize} bytes", 
                    totalCount, estimatedSizeBytes);

                return new RefundStatusExportEstimate
                {
                    TotalCount = totalCount,
                    EstimatedSizeBytes = estimatedSizeBytes,
                    EstimatedDurationMinutes = Math.Max(1, totalCount / 10000) // 估算每万条记录需1分钟
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取导出预估信息失败");
                throw;
            }
        }

        /// <summary>
        /// 导出为多个Sheet的单个Excel文件
        /// </summary>
        private async Task<byte[]> ExportToMultipleExcelAsync(RefundStatusExportRequest request, int totalCount)
        {
            const int maxRowsPerSheet = 1000000; // 每个Sheet最多100万行
            var sheetCount = (int)Math.Ceiling((double)totalCount / maxRowsPerSheet);
            
            _logger.LogInformation("数据量较大{TotalCount}条，将分成{SheetCount}个Sheet", totalCount, sheetCount);
            
            // 设置EPPlus许可证上下文
            ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
            
            using var package = new ExcelPackage();
            
            var processedRows = 0;
            var currentSheetIndex = 1;
            
            await foreach (var batch in GetDataBatchesAsync(request, maxRowsPerSheet))
            {
                var sheetName = sheetCount > 1 ? $"退费情况查询_第{currentSheetIndex}部分" : "退费情况查询";
                var worksheet = package.Workbook.Worksheets.Add(sheetName);
                
                // 设置表头
                var headers = new[]
                {
                    "患者姓名", "身份证号", "预存时间", "期初余额", "当前余额", 
                    "退款结果", "线上退款审核人", "短信联系结果"
                };
                
                for (int i = 0; i < headers.Length; i++)
                {
                    worksheet.Cells[1, i + 1].Value = headers[i];
                    worksheet.Cells[1, i + 1].Style.Font.Bold = true;
                }

                // 如果有多个Sheet，添加说明行
                int startRow = 2;
                if (sheetCount > 1)
                {
                    worksheet.Cells[2, 1].Value = $"说明：这是第{currentSheetIndex}部分，共{sheetCount}部分";
                    worksheet.Cells[2, 1, 2, headers.Length].Merge = true;
                    worksheet.Cells[2, 1].Style.Font.Color.SetColor(System.Drawing.Color.Blue);
                    startRow = 3;
                }
                
                int row = startRow;
                
                foreach (var item in batch)
                {
                    worksheet.Cells[row, 1].Value = item.Name;
                    worksheet.Cells[row, 2].Value = item.IdNumber;
                    worksheet.Cells[row, 3].Value = item.CreateTime;
                    worksheet.Cells[row, 4].Value = item.Balance;
                    worksheet.Cells[row, 5].Value = item.CurrentBalance;
                    worksheet.Cells[row, 6].Value = item.RefundResult;
                    worksheet.Cells[row, 7].Value = item.AuditUserName;
                    worksheet.Cells[row, 8].Value = item.MsgResult;
                    row++;
                }

                // 自动调整列宽
                worksheet.Cells.AutoFitColumns();
                
                processedRows += batch.Count;
                _logger.LogInformation("完成第{CurrentSheet}/{TotalSheets}个Sheet，已处理{ProcessedRows}/{TotalRows}条记录", 
                    currentSheetIndex, sheetCount, processedRows, totalCount);
                
                currentSheetIndex++;
            }
            
            var fileBytes = package.GetAsByteArray();
            _logger.LogInformation("多Sheet Excel导出完成，总Sheet数: {SheetCount}, 文件大小: {FileSize} 字节", 
                sheetCount, fileBytes.Length);
            
            return fileBytes;
        }
        
        /// <summary>
        /// 分批获取数据
        /// </summary>
        private async IAsyncEnumerable<List<dynamic>> GetDataBatchesAsync(RefundStatusExportRequest request, int batchSize)
        {
            var batch = new List<dynamic>();
            
            await foreach (var item in _refundStatusRepository.GetStreamAsync(
                request.Name,
                request.IdNumber,
                request.RefundResult,
                request.CreateTimeStart,
                request.CreateTimeEnd))
            {
                batch.Add(item);
                
                if (batch.Count >= batchSize)
                {
                    yield return batch;
                    batch = new List<dynamic>();
                }
            }
            
            if (batch.Count > 0)
            {
                yield return batch;
            }
        }
        

        
        /// <summary>
        /// 导出为Excel格式（单文件）
        /// </summary>
        private async Task<byte[]> ExportToExcelAsync(RefundStatusExportRequest request)
        {
            // 设置EPPlus许可证上下文
            ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
            
            using var package = new ExcelPackage();
            var worksheet = package.Workbook.Worksheets.Add("退费情况查询");
            
            // 设置表头
            var headers = new[]
            {
                "患者姓名", "身份证号", "预存时间", "期初余额", "当前余额", 
                "退款结果", "线上退款审核人", "短信联系结果"
            };
            
            for (int i = 0; i < headers.Length; i++)
            {
                worksheet.Cells[1, i + 1].Value = headers[i];
                worksheet.Cells[1, i + 1].Style.Font.Bold = true;
            }

            int row = 2;
            
            await foreach (var item in _refundStatusRepository.GetStreamAsync(
                request.Name,
                request.IdNumber,
                request.RefundResult,
                request.CreateTimeStart,
                request.CreateTimeEnd))
            {
                worksheet.Cells[row, 1].Value = item.Name;
                worksheet.Cells[row, 2].Value = item.IdNumber;
                worksheet.Cells[row, 3].Value = item.CreateTime;
                worksheet.Cells[row, 4].Value = item.Balance;
                worksheet.Cells[row, 5].Value = item.CurrentBalance;
                worksheet.Cells[row, 6].Value = item.RefundResult;
                worksheet.Cells[row, 7].Value = item.AuditUserName;
                worksheet.Cells[row, 8].Value = item.MsgResult;
                row++;
                
                // 每1000行记录一次进度
                if (row % 1000 == 0)
                {
                    _logger.LogInformation("Excel导出进度: 已处理 {ProcessedRows} 条记录", row - 2);
                }
            }

            // 自动调整列宽
            worksheet.Cells.AutoFitColumns();
            
            var fileBytes = package.GetAsByteArray();
            
            _logger.LogInformation("Excel导出完成，总行数: {TotalRows}, 文件大小: {FileSize} 字节", 
                row - 2, fileBytes.Length);

            return fileBytes;
        }

        /// <summary>
        /// 导出为CSV格式
        /// </summary>
        private async Task<byte[]> ExportToCsvAsync(RefundStatusExportRequest request)
        {
            using var memoryStream = new MemoryStream();
            using var writer = new StreamWriter(memoryStream, Encoding.UTF8);
            
            // 写入BOM以支持中文
            await writer.WriteAsync('\uFEFF');
            
            // 写入表头
            await writer.WriteLineAsync("患者姓名,身份证号,预存时间,期初余额,当前余额,退款结果,线上退款审核人,短信联系结果");

            int processedRows = 0;
            
            await foreach (var item in _refundStatusRepository.GetStreamAsync(
                request.Name,
                request.IdNumber,
                request.RefundResult,
                request.CreateTimeStart,
                request.CreateTimeEnd))
            {
                var line = $"\"{EscapeCsvField(item.Name)}\",\"{EscapeCsvField(item.IdNumber)}\",\"{EscapeCsvField(item.CreateTime)}\"," +
                          $"{item.Balance},{item.CurrentBalance},\"{EscapeCsvField(item.RefundResult)}\"," +
                          $"\"{EscapeCsvField(item.AuditUserName)}\",\"{EscapeCsvField(item.MsgResult)}\"";
                
                await writer.WriteLineAsync(line);
                processedRows++;
                
                // 每1000行记录一次进度
                if (processedRows % 1000 == 0)
                {
                    _logger.LogInformation("CSV导出进度: 已处理 {ProcessedRows} 条记录", processedRows);
                }
            }

            await writer.FlushAsync();
            
            _logger.LogInformation("CSV导出完成，总行数: {TotalRows}, 文件大小: {FileSize} 字节", 
                processedRows, memoryStream.Length);

            return memoryStream.ToArray();
        }

        /// <summary>
        /// 转义CSV字段
        /// </summary>
        private static string EscapeCsvField(string? field)
        {
            if (string.IsNullOrEmpty(field))
                return "";

            if (field.Contains(',') || field.Contains('"') || field.Contains('\n') || field.Contains('\r'))
            {
                return field.Replace("\"", "\"\"");
            }

            return field;
        }
    }
}
